﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;

namespace KnBinarySerializer.Ver
{
    internal class FormaterPool
    {
        static Type formaterBaseType;
        Dictionary<Type, IFormatter> typeDict;
        Dictionary<byte, IFormatter> keyDict;

        static Dictionary<FormatVer,FormaterPool> poolDict;

        static FormaterPool()
        {
            formaterBaseType = typeof(IFormatter);
            poolDict = new Dictionary<FormatVer, FormaterPool>();
            poolDict.Add(FormatVer.Lastest, new FormaterPool());
            poolDict.Add(FormatVer.Ver1, new FormaterPool());//旧版本1
            //添加所有Formatter
            Assembly asm = Assembly.GetExecutingAssembly();
            Type itype = typeof(IFormatter);
            foreach (Type type in asm.GetTypes())
            {
                if (!type.IsInterface && itype.IsAssignableFrom(type))
                    addFormater(type);
            }
            //addFormater(new Brick.BoolFormatterByteFormatter());
            //addFormater(new Brick.ByteFormatter());
            //addFormater(new Brick.CharFormatter());
            //addFormater(new Brick.DateFormatter());
            //addFormater(new Brick.DecimalFomatter());
            //addFormater(new Brick.DoubleFormatter());
            //addFormater(new Brick.FloatFormatter());
            //addFormater(new Brick.IntFormatter());
            //addFormater(new Brick.LongFormatter());
            //addFormater(new Brick.ShortFormatter());
            //addFormater(new Brick.StringFormatter());
            //addFormater(new None.DBNullFormatter());
            //addFormater(new RuningTypeFormatter());
            //addFormater(new Data.DataSetFormatter());
            //addFormater(new Data.DataTableFormatter());
            //addFormater(new Group.ByteArrayFormatter());
            //addFormater(new ClassFormatterV2());
            //addFormater(new EnumerableFormatter());
            //addFormater(new DictionaryFormatter());
            //再将0号的处理器，补充旧版本可能少的key
            ReSetOldPools();
        }
        public static FormaterPool GetFormaterPool(FormatVer ver)
        {
            return poolDict[ver];
        }
        public FormaterPool()
        {
            typeDict = new Dictionary<Type, IFormatter>();
            keyDict = new Dictionary<byte, IFormatter>();
        }
        private static void addFormater(Type type)
        {
            //新的版本号都会包含所有key的处理，旧的版本号可能只包含部分formater
            IFormatter formatter = (IFormatter)Activator.CreateInstance(type);
            byte key = formatter.GetKey();
            FormatVer ver = FormatVer.Lastest;
            //获取是否指定版本号
            var verAttr = type.GetCustomAttribute<FormatterVerAttribute>();
            if (verAttr != null)
                ver = verAttr.Ver;
            //先按要求的号添加到各自的字典中
            var keyDict = poolDict[ver].keyDict;
            if (keyDict.ContainsKey(key))
                throw new Exception($"key[{key}]重复，添加{type.FullName}失败");
            Type tp = formatter.GetHandleType();
            if (tp != null)//类与列表类使用types标记，都返回null
                poolDict[ver].typeDict.Add(formatter.GetHandleType(), formatter);
            keyDict.Add(key, formatter);
        }

        private static void addFormater(IFormatter formatter, FormatVer ver = FormatVer.Lastest)
        {
            byte key = formatter.GetKey();
            //先按要求的号添加到各自的字典中
            var keyDict = poolDict[ver].keyDict;
            if (keyDict.ContainsKey(key))
                throw new Exception($"key[{key}]重复，添加{formatter.GetType().FullName}失败");
            Type tp = formatter.GetHandleType();
            if (tp != null)//类与列表类使用types标记，都返回null
                poolDict[ver].typeDict.Add(tp, formatter);
            keyDict.Add(key, formatter);
        }

        private static void ReSetOldPools()
        {
            var basePool = poolDict[FormatVer.Lastest];
            foreach(var pool in poolDict)
            {
                if (pool.Key == FormatVer.Lastest)
                    continue;
                var dictKey = pool.Value.keyDict;
                foreach(var key in basePool.keyDict)
                {
                    if (dictKey.ContainsKey(key.Key))
                        continue;
                    dictKey[key.Key] = key.Value;                    
                }
                var dictType = pool.Value.typeDict;
                foreach (var key in basePool.typeDict)
                {
                    if (dictType.ContainsKey(key.Key))
                        continue;
                    dictType[key.Key] = key.Value;
                }
            }
        }

        public IFormatter GetFormatter(object obj)
        {
            Type type = obj.GetType();
            return GetFormatter(type);
        }
        public IFormatter GetFormatter(Type type)
        {            
            if (typeDict.ContainsKey(type))
                return (IFormatter)typeDict[type];

            if (typeof(Type).IsAssignableFrom(type))
                return keyDict[3];

            if (typeof(IDictionary).IsAssignableFrom(type))
                return keyDict[2];

            if (typeof(IEnumerable).IsAssignableFrom(type))
                return keyDict[1];
            else
                return keyDict[0];
        }
        public IFormatter GetFormatter(byte key)
        {
            if (keyDict.ContainsKey(key))
                return (IFormatter)keyDict[key];
            else
                return null;
        }
    }
}
